//
//  dgus_lcd.c
//  实现迪文串口协议的解析
//
//  Created by Eywen on 2021/7/24.
//

#include "dgus_lcd.h"
#include "dg_frame.h"
#include <string.h>
#include "files.h"

static void send_frame_to_lcd(frame_t *frame);
static void dgus_delay_ms(uint32_t ms);
static bool req_show_data_to_dg(uint8_t funcode, int data_num, ...);
static bool req_set_slider(uint16_t addr, uint16_t var);
static bool req_set_widget_var(uint16_t addr, uint16_t var);

bool req_show_text_str(uint16_t addr, char *str);
bool req_show_page(uint16_t page_id);

typedef struct dgus_ui_map{
	dgus_ui_var_addr_t addr;
	dgus_ui_btn_key_t key;
	bool (*handle)(frame_t *frame);
}dgus_ui_btn_handle_map_t;

typedef struct dgus_ui_value_map{
	dgus_ui_var_addr_t addr;
	bool (*handle)(frame_t *frame);
}dgus_ui_value_handle_map_t;

/* 当前文件索引值 */
int s_last_select_file_idx = -1;


/* 根据索引号将字符串名字送入到显示 */
static bool dgus_ui_file_list_set(char *file_name, int idx)
{
    return req_show_text_str(DGUS_UI_FILE_TEXT_1 + idx*20, file_name);
}

bool g_print_flag = false;
/* 处理进入打印页面的准备界面 */
static bool gui_into_print_prepare(frame_t *frame)
{
    if(s_last_select_file_idx > 0){
        //cat(get_select_file_name(s_last_select_file_idx - 1));
        g_print_flag = true;
    }
    return true;
}


/* 主菜单进入打印界面，选择打印文件清单 */
bool gui_into_print_list(frame_t *frame)
{
    char str[DGUS_FILE_TEXT_MAX_LEN];
    int file_cnt = 0;
    /* 读取所有文件名显示到lcd */
    refresh_file_names("/");
    file_cnt = get_cur_dir_file_cnt();
    //debug_info("this");while(1);
    for(int i = 0; i < file_cnt; i++){
        snprintf(str, (int)DGUS_FILE_TEXT_MAX_LEN - 1, "%s", get_cur_dif_file_name(i));
        dgus_ui_file_list_set(str, i);
    }
    /*清空多余的显示文本框*/
    for(int i = file_cnt; i < (int)DGUS_FILE_LIST_TEXT_MAX; i++){
        /* 使用空格清除 */
        snprintf(str, (int)DGUS_FILE_TEXT_MAX_LEN - 1," ");
        dgus_ui_file_list_set(str, i);
    }

	req_show_page(DGUS_PAGE_ID_PRINT_FILE_LIST_0);
	return true;
}

#define DGUS_UI_BTN_FILE_TEXT_HANDLE_MAP(idx)   \
    {                                           \
        .addr = DGUS_UI_VAR_PRINT_LIST_ADDR,    \
        .key  = DGUS_BTN_KEY_FILE_TEXT_##idx,   \
        .handle = gui_file_text_btn_select##idx,    \
    }

/* 保存上次选择的文件索引号 */
#define DGUS_UI_BTN_FILE_TEXT_HANDLE_FUN(idx)   \
static bool gui_file_text_btn_select##idx(frame_t *frame) \
{                                                         \
    int file_cnt = get_cur_dir_file_cnt();                  \
    if(file_cnt >= idx){                                 \
        if(s_last_select_file_idx > 0){                 \
            req_set_widget_var(0x1200 + s_last_select_file_idx - 1, 0);\
        }                                               \
        req_set_widget_var(0x1200 + idx - 1, 1);        \
        s_last_select_file_idx = idx;                   \
        /* 打印变量中更新当前选择的文件名 */             \
        req_show_text_str(DGUS_UI_FILE_TEXT_SELECT, get_cur_dif_file_name(idx - 1)); \
    }                                                   \
    debug_info("%d %d %d ", s_last_select_file_idx, idx, file_cnt); \
    return true;                                        \
}

DGUS_UI_BTN_FILE_TEXT_HANDLE_FUN(1)
DGUS_UI_BTN_FILE_TEXT_HANDLE_FUN(2)
DGUS_UI_BTN_FILE_TEXT_HANDLE_FUN(3)
DGUS_UI_BTN_FILE_TEXT_HANDLE_FUN(4)
DGUS_UI_BTN_FILE_TEXT_HANDLE_FUN(5)
DGUS_UI_BTN_FILE_TEXT_HANDLE_FUN(6)
DGUS_UI_BTN_FILE_TEXT_HANDLE_FUN(7)
DGUS_UI_BTN_FILE_TEXT_HANDLE_FUN(8)
DGUS_UI_BTN_FILE_TEXT_HANDLE_FUN(9)
DGUS_UI_BTN_FILE_TEXT_HANDLE_FUN(10)
DGUS_UI_BTN_FILE_TEXT_HANDLE_FUN(11)
DGUS_UI_BTN_FILE_TEXT_HANDLE_FUN(12)
DGUS_UI_BTN_FILE_TEXT_HANDLE_FUN(13)
DGUS_UI_BTN_FILE_TEXT_HANDLE_FUN(14)
DGUS_UI_BTN_FILE_TEXT_HANDLE_FUN(15)
DGUS_UI_BTN_FILE_TEXT_HANDLE_FUN(16)
DGUS_UI_BTN_FILE_TEXT_HANDLE_FUN(17)
DGUS_UI_BTN_FILE_TEXT_HANDLE_FUN(18)
DGUS_UI_BTN_FILE_TEXT_HANDLE_FUN(19)
DGUS_UI_BTN_FILE_TEXT_HANDLE_FUN(20)

const static dgus_ui_btn_handle_map_t s_dgus_ui_btn_handle[] = 
{
    DGUS_UI_BTN_FILE_TEXT_HANDLE_MAP(1),
    DGUS_UI_BTN_FILE_TEXT_HANDLE_MAP(2),
    DGUS_UI_BTN_FILE_TEXT_HANDLE_MAP(3),
    DGUS_UI_BTN_FILE_TEXT_HANDLE_MAP(4),
    DGUS_UI_BTN_FILE_TEXT_HANDLE_MAP(5),
    DGUS_UI_BTN_FILE_TEXT_HANDLE_MAP(6),
    DGUS_UI_BTN_FILE_TEXT_HANDLE_MAP(7),
    DGUS_UI_BTN_FILE_TEXT_HANDLE_MAP(8),
    DGUS_UI_BTN_FILE_TEXT_HANDLE_MAP(9),
    DGUS_UI_BTN_FILE_TEXT_HANDLE_MAP(10),
    DGUS_UI_BTN_FILE_TEXT_HANDLE_MAP(11),
    DGUS_UI_BTN_FILE_TEXT_HANDLE_MAP(12),
    DGUS_UI_BTN_FILE_TEXT_HANDLE_MAP(13),
    DGUS_UI_BTN_FILE_TEXT_HANDLE_MAP(14),
    DGUS_UI_BTN_FILE_TEXT_HANDLE_MAP(15),
    DGUS_UI_BTN_FILE_TEXT_HANDLE_MAP(16),
    DGUS_UI_BTN_FILE_TEXT_HANDLE_MAP(17),
    DGUS_UI_BTN_FILE_TEXT_HANDLE_MAP(18),
    DGUS_UI_BTN_FILE_TEXT_HANDLE_MAP(19),
    DGUS_UI_BTN_FILE_TEXT_HANDLE_MAP(20),
    {   /* 文件清单页面的打印按钮  */
        .addr = DGUS_UI_VAR_PRINT_LIST_ADDR,
        .key  = DGUS_BTN_KEY_PRINT_START,
        .handle = gui_into_print_prepare,
    },
};
 
const static dgus_ui_value_handle_map_t s_dgus_ui_value_handle_map_list[] = 
{
};
 
 static bool dgus_reg_write_handle(frame_t *frame)
 {
 	debug_info("debug");
     return false;
 }
 
 static bool dgus_reg_read_handle(frame_t *frame)
{
	debug_info("debug");
    return false;
}

static bool dgus_var_write_handle(frame_t *frame)
{
    return false;
}

static bool dgus_var_read_handle(frame_t *frame)
{
	//print_frame(frame);
	int list_size;
	uint16_t addr;
	uint16_t key;
	uint8_t data_len;
	addr = frame_pull_uint16(frame);
	data_len = frame_pull_uint8(frame);
    
    UNUSED(data_len);
    /* 先检查键值变化是否匹配 */
	list_size = sizeof(s_dgus_ui_value_handle_map_list)/sizeof(dgus_ui_value_handle_map_t);
    for(int i = 0; i < list_size; i++){
        if((s_dgus_ui_value_handle_map_list[i].addr == addr) && 
           (s_dgus_ui_value_handle_map_list[i].handle != NULL)){
            return s_dgus_ui_value_handle_map_list[i].handle(frame);
        }
    }

	key  = frame_pull_uint16(frame);
	list_size = sizeof(s_dgus_ui_btn_handle)/sizeof(dgus_ui_btn_handle_map_t);
	//debug_info("addr: %x key: %x size: %d", addr, key, list_size);
	for(int i = 0; i < list_size; i++){
		if((s_dgus_ui_btn_handle[i].addr == addr) && (s_dgus_ui_btn_handle[i].key == key)){
			if(s_dgus_ui_btn_handle[i].handle){
				return s_dgus_ui_btn_handle[i].handle(frame);
			}
			else{
				debug_dg_error_p("handle is null");
			}
		}
	}
    return false;
}


/* 功能码与处理函数表 */
static handle_t s_frame_handle_list[] =
{
    /* 指定地址开始写数据串到寄存器。 */
    {DGUS_REG_WRITE_CMD, dgus_reg_write_handle},       
    /* 从指定寄存器开始读数据。 */
    {DGUS_REG_READ_CMD,  dgus_reg_read_handle},   
    /* 指定地址开始写数据串(字数据)到变量 空间。 */
    {DGUS_VAR_WRITE_CMD, dgus_var_write_handle},  
    /* 从变量空间指定地址开始读指定长度 字数据。 */
    {DGUS_VAR_READ_CMD,  dgus_var_read_handle},      
};

typedef struct handle_t_addr_fun_map
{
    uint16_t addr;
    handle_ptr handle_repy;
}handle_t_addr_fun_map_t;


/* 复位屏幕 */
bool req_sytem_rest(void)
{
    return req_show_data_to_dg(DGUS_VAR_WRITE_CMD, 2, //添加2个数据点
        data_type_uint16, 0x04,     /*复位寄存器地址*/
        data_type_uint32, 0x55AA5AA5);     /*复位指令*/
}

/* 切换lcd的显示页面 */
bool req_show_page(uint16_t page_id)
{
    return req_show_data_to_dg(DGUS_VAR_WRITE_CMD, 3,    /* 后面接3个数据点 */
        data_type_uint16, DGUS_SYS_ADDR_PIC_SET_ADDR,
        data_type_uint16, 0x5a01,                   /* 切页命令 */
        data_type_uint16, page_id);
}

/* 显示字符串到屏幕指定文本标签中去 */
bool req_show_text_str(uint16_t addr, char *str)
{
    if(str == NULL){
        return false;
    }
    
    return req_show_data_to_dg(DGUS_VAR_WRITE_CMD, 3, //添加2个数据点
        data_type_uint16, addr,     /*寄存器地址*/
        data_type_string, str,
        data_type_uint16, 0xffff);     /*显示内容*/
}

bool req_set_slider(uint16_t addr, uint16_t var)
{
	return req_show_data_to_dg(DGUS_VAR_WRITE_CMD, 2, //添加2个数据点
        data_type_uint16, addr,
        data_type_uint16, var);     /*显示内容*/
}

bool req_set_widget_var(uint16_t addr, uint16_t var)
{
	return req_show_data_to_dg(DGUS_VAR_WRITE_CMD, 2, //添加2个数据点
			data_type_uint16, addr,
			data_type_uint16, var); 	/*显示内容*/
}


/* 系统重启 */
static bool repy_system_reset(frame_t *frame)
{
    //debug_p("%s\r\n", __func__);
    return true;
}

/* 
功能： 设置帧功能码、数据域（支持多参数传入）
frame: 帧指针
funcode： 帧功能
data_num： 数据个数

使用举例：
frame_set(frame_ptr, 0x80, 4,   //3表示后面放4个数据点
    data_type_uint8, 0xf1,      //第一个数据点是一个uint8_t类型的
    data_type_float, 3.14,      //第二个数据点是一个float类型的
    data_type_bytes, sizeof(bytes_arr), bytes_arr,  //第三个是字节数组类型
    data_type_string, "hello");   //第四个是字符串类型
注意， 对于uint64类型的数字，必须使用强制(uint64_t)num作为参数传进去，否则编译器
可能优化成int类型到内存引起bug,如果是变量则无所谓。如(uint64_t)3,不加强制时3会被
编译器优化成int到内存。
*/
bool req_show_data_to_dg(uint8_t funcode, int data_num, ...)
{
    va_list v1;
    frame_data_type_t type;
    frame_t *frame;
    frame_t frame_req;
    frame = &frame_req;
    frame_init(frame, funcode);
    
    va_start(v1, data_num);	
    for(int i = 0; i < data_num; i++){
        /* 根据传进来的参数类型确定下一个参数类型，注意一些char、
            uchar的会自动转换为int, float会转换成double */
        type = (frame_data_type_t)va_arg(v1, int);	
        switch(type){
            case data_type_int8:
            case data_type_uint8:
                do{
                    uint8_t data;
                    data = va_arg(v1, uint32_t);
                    frame_push_uint8(frame, data);
                }while(0);
                break;
            case data_type_int16:
            case data_type_uint16:
                do{
                    uint16_t data;
                    data = va_arg(v1, uint32_t);
                    frame_push_uint16(frame, data);
                }while(0);
                break;
            case data_type_int32:
            case data_type_uint32:
                do{
                    uint32_t data;
                    data = va_arg(v1, uint32_t);
                    frame_push_uint32(frame, data);
                }while(0);
                break;
            case data_type_int64:
            case data_type_uint64:
                do{
                    uint64_t data;
                    data = va_arg(v1, uint64_t);
                    frame_push_uint64(frame, data);
                }while(0);
                break;
            case data_type_float:
                do{
                    float data;
                    data = va_arg(v1, double);
                    frame_push_float(frame, data);
                }while(0);
                break;
            case data_type_double:
                do{
                    double data;
                    data = va_arg(v1, double);
                    frame_push_double(frame, data);
                }while(0);
                break;
            case data_type_bytes:
                do{
                    uint8_t *ptr;
                    int bytes_cnt;
                    bytes_cnt = (int)va_arg(v1, int);
					/* 目前只支持32位主板，因此指针都是32位的 */
                    ptr = (uint8_t *)va_arg(v1, int);
					/* 如果有64位cpu，换成下面的 */
					/*
					ptr = (uint8_t *)((sizeof(int *) == 8)?(va_arg(v1, uint64_t)):
						va_arg(v1, int));
						*/
                    frame_push_bytes(frame, ptr, bytes_cnt);
                }while(0); 
                break;
            case data_type_string:
                do{
                    char *ptr;
                    ptr = (char *)va_arg(v1, int);
                    frame_push_string(frame, ptr);
                }while(0); 
                break;
            default: //错误
                debug_dg_warning_p("error frame_data_type_t\r\n");
                break;
        }
    }
    va_end(v1);
    /* 组装好帧校验和长度 */
    frame_repy_create(frame);
    send_frame_to_lcd(frame);
    //print_frame(&frame_req);
    return true;
}

/* 地址操作与回复处理函数映射 */
handle_t_addr_fun_map_t addr_fun_map_list[] = {
    {0x06, repy_system_reset}, /* System_Reset */
};

/* 迪文屏发送来的数据接收缓存 */
uint8_t g_lcd_frame_raw_buff[FRAME_BUS_BUFF_LEN];

handle_t *get_dgus_handle(void)
{
    return s_frame_handle_list;
}

/* 发送回复数据 */
void send_frame_to_lcd(frame_t *frame)
{
    extern rt_device_t serial;
	int frame_len;
	frame_len = get_frame_len(frame);
	rt_device_write(serial, 0, frame->buff, frame_len);
}

static void dgus_delay_ms(uint32_t ms)
{
    delay_ms(ms);
}


/* 串口接收所有的数据 */
static int recv_all_dgus_serial_data(uint8_t *recv)
{
    extern rt_device_t serial;
    /* 用于接收消息的信号量 */
    extern struct rt_semaphore rx_sem;
    uint16_t len;
    uint8_t ch;
    int timeout;
    len = 0;

    if(rt_device_read(serial, 0, &ch, 1) != 1){
        return 0;
    }
    recv[len++] = ch;

    timeout = 0;
    while(timeout < 1000){
        /* 等待接收到数据 */
        if(rt_device_read(serial, 0, &ch, 1) == 1){
            recv[len++] = ch;
            timeout = 0;
        }
        else{
            rt_thread_mdelay(1);
            timeout++;
        }
    }

    debug_hex(recv, len);
    return len;
}


/* gui的全局变量初始化 */
static bool dgus_gui_init(void)
{
    //s_last_select_file_idx = -1;
    return true;
}


/* 开机启进度界面和进入主菜单 */
bool dgus_ui_setup(void)
{
	req_show_page(DGUS_PAGE_ID_PRINT_FILE_LIST_0);
	/* 取消上次显示的文本选择框 */
	for(int i = 0; i < 4; i++){
	    req_set_widget_var(0x1200 + i, 0);
	}
	return true;
}


/* 刷新UI */
static bool dgus_ui_refresh(void)
{
    return true; 
}


/* UI刷新间隔 毫秒  */
#define DGUS_UI_REFRESH_TIME_MS        (1000)


bool dgus_task_handle(void)
{
	uint8_t dgus_rev_buff[FRAME_BUS_BUFF_LEN];
	int len;
	len = recv_all_dgus_serial_data(dgus_rev_buff);
    /* 收到数据才处理  */
	if(len != 0){
		//debug_hex(dgus_rev_buff, len);
		/* 解码，分割、提取各条完整帧  */
		if(deframe(dgus_rev_buff, len) != ok_integrity){
			debug_info("frame error");
			return false;
		}

		//将上一步解码成功的帧依次处理，处理函数表为参数
		return handle_frame_buff(get_dgus_handle(),
				sizeof(s_frame_handle_list)/sizeof(handle_t));
	}

    /* 定时刷新UI数字内容 */
	static int last_time = 0;

    if((rt_tick_get_millisecond() - last_time) > DGUS_UI_REFRESH_TIME_MS){
        dgus_ui_refresh();
        last_time = rt_tick_get_millisecond();

    }

	return true;
}

